package com.weishuang.monitor.leader.service.impl;

import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.weishuang.monitor.leader.commons.enums.SERVERCODE;
import com.weishuang.monitor.leader.entity.ServerWarnInfo;
import com.weishuang.monitor.leader.entity.vo.ServersBaseInfoVO;
import com.weishuang.monitor.leader.mapper.ServerCpuRealTimeMapper;
import com.weishuang.monitor.leader.mapper.ServerDiskInfoMapper;
import com.weishuang.monitor.leader.mapper.ServerRamRealTimeMapper;
import com.weishuang.monitor.leader.mapper.ServerWarnInfoMapper;
import com.weishuang.monitor.leader.service.IServerWarnInfoService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author weishuang
 * @since 2021-04-23
 */
@Slf4j
@Service
public class ServerWarnInfoServiceImpl extends ServiceImpl<ServerWarnInfoMapper, ServerWarnInfo> implements IServerWarnInfoService {

    @Autowired
    private ServerCpuRealTimeMapper serverCpuRealTimeMapper;
    @Autowired
    private ServerRamRealTimeMapper serverRamRealTimeMapper;
    @Autowired
    private ServerDiskInfoMapper serverDiskInfoMapper;

    @Autowired
    private EmailSendService emailSendService;

    @Value("${leader.warn.DateScope.cpu:60}")
    private Long dateScopeCpu;

    @Value("${leader.warn.threshold.cpu:90}")
    private Long thresholdCpu;

    @Value("${leader.warn.warnRule.cpu:1440}")
    private Long warnRuleCpu;

    @Value("${leader.warn.DateScope.ram:60}")
    private Long dateScopeRam;

    @Value("${leader.warn.threshold.ram:90}")
    private Long thresholdRam;

    @Value("${leader.warn.warnRule.ram:1440}")
    private Long warnRuleRam;

    @Value("${leader.warn.threshold.disk:90}")
    private Long thresholdDisk;

    @Value("${leader.warn.warnRule.disk:1440}")
    private Long warnRuleDisk;

    /**
     * 执行Cpu使用率预警检查
     */
    @Override
    public void serverCpuWarnCheck() {
        // 获取一分钟内的cpu实时数据，并根据服务Id进行分组。然后进行计算占用率，超过进行预警
        //计算时间范围
        Date date = new Date(new Date().getTime() - (dateScopeCpu * 1000));
        List<ServersBaseInfoVO> serversBaseInfos = serverCpuRealTimeMapper.getOnlineServersCpuAVG(date,thresholdCpu);
        this.serverwarnDateDispose(serversBaseInfos,SERVERCODE.WARN_TYPE_CPU.getValue(),warnRuleCpu,null);
    }

    /**
     * 执行Ram使用率预警
     */
    @Override
    public void serverRamWarnCheck() {
        Date date = new Date(new Date().getTime() - (dateScopeRam * 1000));
        List<ServersBaseInfoVO> serversBaseInfos = serverRamRealTimeMapper.getOnlineServersRamAVG(date,thresholdRam);
        this.serverwarnDateDispose(serversBaseInfos,SERVERCODE.WARN_TYPE_RAM.getValue(),warnRuleRam,null);
    }

    /**
     * 执行Disk使用率预警
     */
    @Override
    public void serverDiskWarnCheck() {
        List<ServersBaseInfoVO> serversBaseInfos = serverDiskInfoMapper.getOnlineServersDiskAVG(thresholdDisk);
        if (serversBaseInfos != null && serversBaseInfos.size() > 0) {
            for (ServersBaseInfoVO serversBaseInfo : serversBaseInfos) {
                List<ServersBaseInfoVO> serversBaseInfoVOS = new ArrayList<>(1);
                serversBaseInfoVOS.add(serversBaseInfo);
                this.serverwarnDateDispose(serversBaseInfoVOS, SERVERCODE.WARN_TYPE_DISK.getValue(), warnRuleDisk, serversBaseInfo.getDiskUuid());
            }
        }

    }

    @Transactional(rollbackFor = Exception.class)
    public void serverwarnDateDispose(List<ServersBaseInfoVO> serversBaseInfos,String warnType,Long warnRule, String diskUuid) {
        //cpu预警列表。进行保存后发送预警信息
        Date warnRuleDate = new Date(new Date().getTime() - (warnRule * 1000 * 60));
        if (serversBaseInfos != null && serversBaseInfos.size() > 0) {
            //查询预警列表，如果存在阈值范围内的预警就不进行预警
            List<String> warnSysId = baseMapper.listOnlineServersIdByWarnRule(warnRuleDate, warnType,diskUuid);
            if (warnSysId == null) {
                warnSysId = new ArrayList<>();
            }
            for (ServersBaseInfoVO serversBaseInfo : serversBaseInfos) {
                if (warnSysId.contains(serversBaseInfo.getId())) {
                    //存在，不进行预警
                    continue;
                }else{
                    //不存在，进行新增预警
                    ServerWarnInfo serverWarnInfo = new ServerWarnInfo();
                    serverWarnInfo.setId(IdWorker.getIdStr());
                    serverWarnInfo.setSysId(serversBaseInfo.getId());
                    serverWarnInfo.setWarnType(warnType);
                    serverWarnInfo.setWarnStatus(SERVERCODE.WARN_STATUS_OPEN.getValue());
                    serverWarnInfo.setWarnValue(serversBaseInfo.getUsageRate());
                    serverWarnInfo.setUpdatedTime(new Date());
                    serverWarnInfo.setDiskUuid(diskUuid);
                    baseMapper.insert(serverWarnInfo);
                    //发送预警
                    this.sendWarnInfo(serversBaseInfo, serverWarnInfo);
                }
            }
        }else{
            //修改阈值范围外的预警状态为关闭
            LambdaUpdateWrapper<ServerWarnInfo> lt = Wrappers.lambdaUpdate(ServerWarnInfo.class)
                    .set(ServerWarnInfo::getWarnStatus, SERVERCODE.WARN_STATUS_CLOZE.getValue())
                    .eq(ServerWarnInfo::getWarnStatus, SERVERCODE.WARN_STATUS_OPEN.getValue())
                    .lt(ServerWarnInfo::getUpdatedTime, warnRuleDate);
            this.update(lt);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void sendWarnInfo(ServersBaseInfoVO serversBaseInfo, ServerWarnInfo serverWarnInfo) {
        if (SERVERCODE.WARN_TYPE_CPU.getValue().equals(serverWarnInfo.getWarnType())) {
            String subject = "%sCpu高负载预警";
            String content = "%sCpu高负载预警 \n" +
                    "CPU使用率：%s %% \n" +
                    "CPU使用率阈值：%s %% \n" +
                    "服务器类型：%s \n" +
                    "服务器版本：%s";
            emailSendService.sendEmail(
                    String.format(subject, serversBaseInfo.getSystemName()),
                    String.format(content, serversBaseInfo.getSystemName(), serversBaseInfo.getUsageRate(), thresholdCpu, serversBaseInfo.getSystemType(), serversBaseInfo.getSystemVersion()));
        }else if (SERVERCODE.WARN_TYPE_CPU.getValue().equals(serverWarnInfo.getWarnType())) {
            String subject = "%sRam高负载预警";
            String content = "%sRam高负载预警 \n" +
                    "Ram使用率：%s %% \n" +
                    "Ram使用率阈值：%s %% \n" +
                    "服务器类型：%s \n" +
                    "服务器版本：%s";
            emailSendService.sendEmail(
                    String.format(subject, serversBaseInfo.getSystemName()),
                    String.format(content, serversBaseInfo.getSystemName(), serversBaseInfo.getUsageRate(), thresholdRam, serversBaseInfo.getSystemType(), serversBaseInfo.getSystemVersion()));
        }else if (SERVERCODE.WARN_TYPE_DISK.getValue().equals(serverWarnInfo.getWarnType())) {
            String subject = "%sDisk高负载预警";
            String content = "%sDisk高负载预警 \n" +
                    "Disk使用率：%s %% \n" +
                    "Disk使用率阈值：%s %% \n" +
                    "磁盘名称：%s \n" +
                    "服务器类型：%s \n" +
                    "服务器版本：%s";
            emailSendService.sendEmail(
                    String.format(subject, serversBaseInfo.getSystemName()),
                    String.format(content, serversBaseInfo.getSystemName(), serversBaseInfo.getUsageRate(), thresholdDisk, serversBaseInfo.getDiskName(),serversBaseInfo.getSystemType(), serversBaseInfo.getSystemVersion()));
        }else{
            log.info("无法判断的预警数据！");
        }

    }

}
